原文:8.17. copy — Shallow and deep copy operations Python中的赋值语句并不拷贝对象,而是创建目标和对象之间的绑定关系。对于那些可变的或包含可变对象的集合来说,有时候需要进行拷贝,以使得一个对象的改变并不会改变另一个对象。这个模块提供常规的浅拷贝操作和深拷贝操作(解释如下)。
接口概述:
copy.copy(x)
返回x的一个浅拷贝 copy.deepcopy(x)
返回x的一个深拷贝 exception copy.error
模块的特定错误
浅拷贝和深拷贝之间的不同仅在于复合对象(即包含其他对象的对象,例如列表或者类实例): * 一个浅拷贝创建一个新的复合对象,然后(尽可能地)插入原始对象中的对象的 引用。 * 一个深拷贝创建一个新的复合对象,然后迭代地插入原始对象中的对象的 拷贝。
两个在深拷贝操作中常见的问题(浅拷贝不存在这两个问题): * 递归对象(直接或间接包含自身的一个引用的复合对象)可能导致递归循环 * 由于深拷贝拷贝 一切,因此它可能会过多拷贝。例如,即使在副本之间,管理数据结构也应该被共享。
deepcopy()
函数通过以下方式来避免这些问题: * 维护一个当前已拷贝对象的"备忘录"字典 * 允许用户定义的类重写拷贝操作或一组组件拷贝。
这个模块不会拷贝下述类型:模块,方法,堆栈跟踪,堆栈帧,文件,socket,窗口,数组或任何类似类型。 它通过返回不变的原始对象来“拷贝”函数和类(浅拷贝,深拷贝)。这与pickle模块的处理方式兼容。
字典的浅拷贝可以使用dict.copy()
,而列表的浅拷贝可以通过将整个列表的切片赋值给它,例如:copied_list = original_list[:]
2.5版本修改:新增拷贝函数。
类可以使用与控制pickling相同的接口来控制拷贝。查看模块pickle的描述以获得关于这些方法的信息。copy模块并不使用copy_reg注册模块。
若想为一个类定义它自己的拷贝实现方式,可以定义特殊的方法 copy() 和 deepcopy()。前者被调用来实现浅拷贝操作;不需要传递额外的参数。后者被调用来实现深拷贝操作;需要传递一个参数,“备忘录”字典。如果 deepcopy()实现需要创建一个组件的深拷贝,它应该调用deepcopy函数,并把这个组件作为第一个参数,“备忘录”字典作为第二个参数传递。
碎碎念
先举个例子: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40range(0,5) a =
range(7,9)) a.append(
b = a
import copy
c = copy.copy(a)
d = copy.deepcopy(a)
a
[0, 1, 2, 3, 4, [7, 8]]
b
[0, 1, 2, 3, 4, [7, 8]]
c
[0, 1, 2, 3, 4, [7, 8]]
d
[0, 1, 2, 3, 4, [7, 8]]
777) a.append(
5].append('c') a[
a
[0, 1, 2, 3, 4, [7, 8, 'c'], 777]
b
[0, 1, 2, 3, 4, [7, 8, 'c'], 777]
c
[0, 1, 2, 3, 4, [7, 8, 'c']]
d
[0, 1, 2, 3, 4, [7, 8]]
id(a)
3066904664L
id(b)
3066904664L
id(c)
3066908544L
id(d)
3066904624L
id(a[5])
3066821928L
id(b[5])
3066821928L
id(c[5])
3066821928L
id(d[5])
3066905824L